//
// Created by gastonfeng on 2022/9/26.
//

#ifndef RTE_KB9115_USBIPSERVER_H
#define RTE_KB9115_USBIPSERVER_H

#ifdef USE_FREERTOS
#include <FreeRTOS.h>
#endif

#include <ESP8266WiFi.h>

#define htons(x) ( ((x)<< 8 & 0xFF00) | \
                   ((x)>> 8 & 0x00FF) )
#define ntohs(x) htons(x)

#define htonl(x) ( ((x)<<24 & 0xFF000000UL) | \
                   ((x)<< 8 & 0x00FF0000UL) | \
                   ((x)>> 8 & 0x0000FF00UL) | \
                   ((x)>>24 & 0x000000FFUL) )
#define ntohl(x) htonl(x)


#define USB_DEVICE_VENDOR_ID  0x16c0
#define USB_DEVICE_PRODUCT_ID 0x05df
#define USB_DEVICE_VERSION    0x0130

#define USB_HID_MAX_PACKET_SIZE 64

#include "DAP_config.h"
#include "DAP.h"


#include "usb_defs.h"
#include "usbip_defs.h"
#include "smodule.h"


#define STR_ILANGUAGES_SUPPORTED 0
#define STR_IMANUFACTURER 1
#define STR_IPRODUCT      2
#define STR_ISERIAL       3

#define USBIP_SERVER_PORT 3240

class USBIPServer {
public:

    enum state_t {
        ACCEPTING,
        ATTACHING,
        EMULATING,
    };

    typedef int (*callback_t)(void *data_in, void *data_out);

    explicit USBIPServer(callback_t on_hid_data);

    void begin();


    void loop();

    void accept();

    void attach();

    void emulate();


protected:

    void write(void *data, int size);

    void send_stage2_submit(usbip_stage2_header &req_header, int32_t status, int32_t data_length);

    void send_stage2_submit_data(usbip_stage2_header &req_header, int32_t status, void *data, int32_t data_length);

    void send_stage2_unlink(usbip_stage2_header &req_header);


    void send_stage1_header(uint16_t command, uint32_t status);

    void send_device_list();

    void send_device_info();

    void send_interface_info();


    int read_stage1_command();

    int read_stage2_command(usbip_stage2_header &header);


    void pack(void *data, int size);

    void unpack(void *data, int size);


    // handlers:

    // stage 1:

    void handle_device_list();

    void handle_device_attach();

    // stage 2:

    void handle_submit(usbip_stage2_header &header);

    void handle_unlink(usbip_stage2_header &header);


    // stage 2 helpers:

    void handle_control_request(usbip_stage2_header &header);

    void handle_data_request(usbip_stage2_header &header);

    void handle_data_response(usbip_stage2_header &header);


    void handle_get_descriptor(usbip_stage2_header &header);

    void handle_get_device_descriptor(usbip_stage2_header &header);

    void handle_get_configuration_descriptor(usbip_stage2_header &header);

    void handle_get_string_descriptor(usbip_stage2_header &header);

    void handle_get_interface_descriptor(usbip_stage2_header &header);

    void handle_get_endpoint_descriptor(usbip_stage2_header &header);

    void handle_get_device_qualifier_descriptor(usbip_stage2_header &header);

    void handle_get_hid_report_descriptor(usbip_stage2_header &header);


    void handle_set_configuration(usbip_stage2_header &header);

    void handle_set_idle(usbip_stage2_header &header);


    void send_stage2_configuration_descriptor();

    void send_stage2_interface_descriptor();

    void send_stage2_hid_descriptor();

    void send_stage2_endpoint_descriptors();

private:

    uint8_t data_in[USB_HID_MAX_PACKET_SIZE];
    uint8_t data_out[USB_HID_MAX_PACKET_SIZE];

    bool respond;

    state_t state;

    callback_t on_hid_data;

    WiFiServer wifiServer;

    WiFiClient client;
};

#endif //RTE_KB9115_USBIPSERVER_H
